import { LineString, Polygon} from 'ol/geom'
import {getArea, getLength} from 'ol/sphere'
import {unByKey} from 'ol/Observable'
import { OlDraw, OlOverlay } from './type'
import { commonStyle } from './utils'
/**
 * 小工具类
 */
class WTool {
  constructor (map, option = {}) {
    const { style, unit = 'km'} = option
    this.map = map
    this.draw = null // 当前绘制的图形对象
    this.sketch = null // 当前绘制的图形对应的featrue
    this.unit = unit // 进制单位
    this.helpTooltipElement = null // 提示框element
    this.helpTooltip = null // 提示框对象
    this.measureTooltipElement = null
    this.measureTooltip = null
    this.featureData = null
    this.events = ['done'] // 支持的事件
    this.WEvents = new Map() // 存储事件
    this.style = commonStyle(style)
    this.initGraph()
  }
  /**
	 * 初始化矢量图形
	 */
	initGraph() {
    this.map.on('pointermove', (e) => this.pointerMoveHandler(e))
    this.map.getViewport().addEventListener('mouseout', () => {
      this.helpTooltipElement && this.helpTooltipElement.classList.add('WMap-hidden')
    })
		// 取到map类已实例化的矢量图层
		if (this.map.getVectorLayer()) {
			this.vector = this.map.getVectorLayer()
			this.source = this.vector.getSource()
			this.setStyle(this.style)
		} else {
			this.source = new VectorSource({ wrapX: false })
			this.vector = new VectorLayer({
				className: 'WMap-vector-layer',
				// 数据源
				source: this.source,
				// 样式
				style: () => {
					const styles = this.style
					return styles
				}
			})
			this.map.addLayer(this.vector) // 添加到图层上
		}
	}
  /**
   * 设置样式
   */
  setStyle(style) {
    this.style = style
    this.vector.setStyle(this.style)
  }
  /**
   * 获取样式
   */
  getStyle() {
    return this.style
  }
  /**
   * 鼠标移上去时候的操作
   * @param {*} evt 
   * @returns 
   */
  pointerMoveHandler (evt) {
    if (evt.dragging) {
      return
    }
    let helpMsg = '点击开始测量'
    if (this.sketch) {
      const geom = this.sketch.getGeometry()
      if (geom instanceof Polygon) {
        helpMsg = '点击继续测量面积'
      } else if (geom instanceof LineString) {
        helpMsg = '点击继续测量长度'
      }
    }
    this.helpTooltipElement && (this.helpTooltipElement.innerHTML = helpMsg)
    this.helpTooltip && this.helpTooltip.setPosition(evt.coordinate)
    this.helpTooltipElement && this.helpTooltipElement.classList.remove('WMap-hidden')
  }
  /**
   * 长度.
   * @param {LineString} line The line.
   * @return {string} The formatted length.
   */
  formatLength (line) {
    const length = getLength(line)
    let output
    if (this.unit === 'km') {
      output = Math.round((length / 1000) * 100) / 100
    } else {
      output = Math.round(length * 100) / 100
    }
    return {
      originData: output,
      data: this.unit === 'km' ?  output + ' ' + 'km' : output + ' ' + 'm'
    }
  }
  /**
   * 面积.
   * @param {Polygon} polygon The polygon.
   * @return {string} Formatted area.
   */
  formatArea (polygon) {
    const area = getArea(polygon)
    let output
    if (this.unit === 'km') {
      output = Math.round((area / 1000000) * 100) / 100
    } else {
      output = Math.round(area * 100) / 100
    }
    return {
      originData: output,
      data: this.unit === 'km' ? output + ' ' + 'km<sup>2</sup>' : output + ' ' + 'm<sup>2</sup>'
    }
  }
  startDraw (types) {
    this.map.on('pointermove', (e) => this.pointerMoveHandler(e))
    let type = ''
    switch (types) {
      case 'distance':
        type = 'LineString'
        break
      case 'area':
        type = 'Polygon'
        break
      default:
        type = 'LineString'
        break
    }
    this.draw = new OlDraw({
      source: this.source,
      type: type,
      style: this.style
    })
    this.map.addGraph(this.draw)
    // 每次主动绘制时overlay的唯一关联对应
    const onlyId = String(Date.now()).slice(6)
    this.createMeasureTooltip(onlyId)
    this.createHelpTooltip(onlyId)
    let listener
    let output // 输出数据
    let origin // 原始数据
    let _this = this
    this.draw.setActive(true)
    this.draw.on('drawstart', function (evt) {
      // set sketch
      this.sketch = evt.feature
      let tooltipCoord = evt.coordinate
      listener = this.sketch.getGeometry().on('change', function (evt) {
        const geom = evt.target
        if (geom instanceof Polygon) {
          const { originData , data } = _this.formatArea(geom)
          output = data
          origin = originData
          tooltipCoord = geom.getInteriorPoint().getCoordinates()
        } else if (geom instanceof LineString) {
          const { originData , data } = _this.formatLength(geom)
          output = data
          origin = originData
          tooltipCoord = geom.getLastCoordinate()
        }
        _this.measureTooltipElement.innerHTML = output
        _this.measureTooltip.setPosition(tooltipCoord)
      })
    })
    this.draw.on('drawend', function (e) {
      _this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-static'
      _this.measureTooltip.setOffset([0, -7])
      _this.sketch = null
      // let data = _this.measureTooltipElement.innerHTML
      _this.measureTooltipElement = null
      _this.createMeasureTooltip(onlyId)
      unByKey(listener)
      _this.close()
      let targets = _this.WEvents.get('WTool(done)')
      if (targets) {
        _this.featureData = {
          type: types,
          data: origin,
          unit: _this.unit,
          feature: {
            feature: e.feature, // feature矢量图
            tip: _this.measureTooltip // 提示语dom
          }
        }
        window.dispatchEvent(targets.costomEvent)
      }
    })
  }
  createHelpTooltip(onlyId) {
    if (this.helpTooltipElement) {
      this.helpTooltipElement.parentNode.removeChild(this.helpTooltipElement)
    }
    this.helpTooltipElement = document.createElement('div')
    this.helpTooltipElement.className = 'ol-tooltip WMap-hidden'
    this.helpTooltip = new OlOverlay({
      element: this.helpTooltipElement,
      offset: [15, 0],
      positioning: 'center-left',
      extData: {
        onlyId
      }
    })
    this.map.add(this.helpTooltip)
  }
  createMeasureTooltip(onlyId) {
    if (this.measureTooltipElement) {
      this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement)
    }
    this.measureTooltipElement = document.createElement('div')
    this.measureTooltipElement.className = 'ol-tooltip ol-tooltip-measure'
    this.measureTooltip = new OlOverlay({
      element: this.measureTooltipElement,
      offset: [0, -15],
      positioning: 'bottom-center',
      stopEvent: false,
      insertFirst: true,
      extData: {
        onlyId
      }
    })
    this.map.add(this.measureTooltip)
  }
  /**
   * 测距离
   */
  distance () {
    this.startDraw('distance')
  }
  /**
   * 面积
   */
  area () {
    this.startDraw('area')
  }
  /**
   * 普通标记
   */
  single () {

  }
  /**
   * 关闭小工具
   */
  close () {
    this.draw && this.map.removeGraph(this.draw)
    this.draw.setActive(false)
    this.clearHelpTooltip()
  }
  /**
   * 清除提示框
   */
  clearHelpTooltip () {
    this.map.off('pointermove')
    this.helpTooltipElement.classList.add('WMap-hidden')
    this.helpTooltipElement.innerHTML = ''
    this.helpTooltip.setPosition(undefined)
  }
  /**
   * 删除对应的矢量图形
   * @param {*} feature
   */
  remove(feature) {
    feature.feature && this.map.getVectorLayer().getSource().removeFeature(feature.feature)
    if (feature.tip) {
      // 循环遍历删除overlay， 因为每次主动绘制，都会调用两次createMeasureTooltip和一次createHelpTooltip
      this.map.getOverlays().forEach(item => {
        if (item?.options?.extData?.onlyId) {
          if (item.options.extData.onlyId === feature.tip.options.extData.onlyId) {
            this.map.removeOverlay(item)
          }
        }
      })
    }
  }
  // 事件注册
	on(eventName, callBack = () => {}) {
		if (!eventName || typeof eventName !== 'string') throw new Error('请传入正确的 eventName！')
		if (!this.events.includes(eventName)) return console.warn('无效的事件：' + eventName)
		const eventObject = {
			eventName: 'WTool(' + eventName + ')',
			callBack,
			handler: e => {
				e.callBack({
					type: e.eventName,
					target: e.target,
					event: e.event
				})
			}
		}
		// 未绑定过事件
		if (!this.WEvents.has(eventObject.eventName)) {
			if (eventObject.eventName === 'WTool(' + eventName + ')') {
				let eve = document.createEvent('HTMLEvents')
				eve.initEvent(eventObject.eventName, false, true)
				eve.callBack = callBack
				eventObject.costomEvent = eve
				window.addEventListener(eventObject.eventName, e => {
          return e.callBack && e.callBack({
            data: this.featureData
          })
        })
			}
			//储存事件
			this.WEvents.set(eventObject.eventName, eventObject)
		}
		this.olTarget && this.olTarget.set('WEvents', this.WEvents)
	}
	//事件移除
	off(eventName, callBack = () => {}) {
		eventName = 'WTool(' + eventName + ')'
		if (this.WEvents.has(eventName)) {
			// 获取事件对象
			const currentEventObject = this.WEvents.get(eventName)
			// 移除事件
			this.olTarget.un(currentEventObject.eventName, currentEventObject.handler)
			// 删除事件存储
			this.WEvents.delete(eventName)
			this.olTarget && this.olTarget.set('WEvents', this.WEvents)
			callBack()
		}
	}
}

export default WTool
